# This module manages the interactions with the corporate LDAP server
# and hadles the logic for protecting against duplate entries for the
# same user in the aplication database

require 'ldap'

module EnotifyLdap


    
    SEARCH_BASE = 'ou=active,ou=employees,ou=people,o=cisco.com'
    
    FIELD_EMPLOYEE_IDS = 'directreports'
    
    FIELD_MANAGER_EMPLOYEE_NUMBER = 'manageruid'
    
    FIELD_EMPLOYEE_NUMBER = 'employeenumber'
    
    FIELD_EMPLOYEE_UID = 'uid'
    
    FIELD_EMPLOYEE_LAST_NAME = 'sn'
    
    FIELD_EMPLOYEE_PREFERED_FIRST_NAME = 'nickname'
    
    FIELD_EMPLOYEE_GIVEN_FIRST_NAME = 'givenName'
    
    REQUESTED_ATTRIBUTES = [FIELD_EMPLOYEE_PREFERED_FIRST_NAME, FIELD_EMPLOYEE_GIVEN_FIRST_NAME, FIELD_EMPLOYEE_LAST_NAME,
                            FIELD_MANAGER_EMPLOYEE_NUMBER, FIELD_EMPLOYEE_NUMBER, FIELD_EMPLOYEE_IDS, FIELD_EMPLOYEE_UID]
    
    ##
    # this is a test method it is not used by the application
    def get_full_person_from_ldap_by_username(username)
    
        conn = _setup_ldap()
        search_filter = FIELD_EMPLOYEE_UID + '=' + username
        person = Person.new
        
        conn.search(SEARCH_BASE, LDAP::LDAP_SCOPE_SUBTREE, search_filter) { |entry|
            puts entry.inspect
        }
    
    end 
    
    ##
    #  Checks LDAP for this username. Returns a new person object 
    #   containing the username and users full name if the username
    #   is found in LDAP.  
    #   If there is no match for the username in LDAP nil is returned. 
    def get_person_from_ldap_by_username(username)
    
        conn = _setup_ldap()
        search_filter = FIELD_EMPLOYEE_UID + '=' + username
        
        # get the person if they are in the DB  
        person = Person.find_by_username(username)
        

        # get the person's info out of LDAP if it exists
        if (person.nil?)
           puts "starting ldap lookup"
            conn.search(SEARCH_BASE, LDAP::LDAP_SCOPE_SUBTREE, search_filter) { |entry|
              
              user_hash = entry.to_hash
              person = Person.new
              person.first_name = user_hash[FIELD_EMPLOYEE_PREFERED_FIRST_NAME].to_s
              person.last_name = user_hash[FIELD_EMPLOYEE_LAST_NAME].to_s
              person.username = username.to_s
              
              if person.first_name.empty?
                  #they don't have a nickname, so use their given name
                  person.first_name = user_hash[FIELD_EMPLOYEE_GIVEN_FIRST_NAME].to_s
              end
            }
        end
       
        ## this will be nil if the username isn't in LDAP
        return person
    
    end 
    
    ##
    # gets an array of person object for all of the people that
    # directly report to the username provided.                        
    def get_array_of_employees_from_ldap_by_manager_username(username) 
       
        conn = _setup_ldap()
        search_filter = FIELD_EMPLOYEE_UID + '=' + username
    
        team_of_people = Array.new()
        
        direct_report_string = nil
    
        person = Person.new
        
        conn.search(SEARCH_BASE, LDAP::LDAP_SCOPE_SUBTREE, search_filter, REQUESTED_ATTRIBUTES) { |entry|
            #puts entry.inspect
            user_hash = entry.to_hash
            direct_report_string = user_hash[FIELD_EMPLOYEE_IDS].to_s
        }
    
        # if you don't find the manager, don't bother trying to find the team
        if direct_report_string.empty?
            return nil
        end
    
        ## get the employees for this manager
        if !direct_report_string.nil?
            direct_report_string.split(':').each do |number|
                team_member = get_person_by_employee_number(number)
                if !team_member.nil?
                  team_of_people.push(team_member)
                end
            end
        end
    
        ## return nothing if we don't have a team
        if team_of_people.length == 0
            return nil
        end
        
        return team_of_people
    
    end 
    
    ##
    # Takes an employee number and returns a person object for that person.
    def get_person_by_employee_number(employeenumber)
    
        conn = _setup_ldap()
        search_filter = FIELD_EMPLOYEE_NUMBER + '=' + employeenumber
        person = nil
        conn.search(SEARCH_BASE, LDAP::LDAP_SCOPE_SUBTREE, search_filter, REQUESTED_ATTRIBUTES) { |entry|
            #puts entry.inspect
            user_hash = entry.to_hash
            
            ## this isn't the most efficient way to get the user since we are basically
            ## double dipping into LDAP, but it eliminates complexity in dealing with
            ## duplicates between the LDAP and Application DB.
            person = get_person_from_ldap_by_username(user_hash[FIELD_EMPLOYEE_UID].to_s)
            
        }
        
        return person
    end
    
    
    def _setup_ldap()
        return LDAP::Conn.new(host='ldap.cisco.com')
    end
    

end